﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IronLua
{
    internal sealed class ClrInteropDictionaryWrapper<TKey, TValue>
        : IDictionary<Value, Value>
    {

        private readonly Type keyType;
        private readonly Type valueType;
        private readonly IDictionary<TKey, TValue> data;
        private readonly dynamic dynData;

        public ClrInteropDictionaryWrapper(IDictionary<TKey, TValue> data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            this.keyType = typeof(TKey);
            this.valueType = typeof(TValue);
            this.data = data;
            this.dynData = data;
        }

        public void Add(Value key, Value value)
        {
            var clrkey = key.ToClrValue();
            var clrvalue = value.ToClrValue();
            this.dynData.Add(clrkey, clrvalue);
        }

        public bool ContainsKey(Value key)
        {
            return this.dynData.ContainsKey(key.ToClrValue());
        }

        public ICollection<Value> Keys { get { return ClrInterop.ToLuaValueCollection(this.data.Keys); } }

        public bool Remove(Value key)
        {
            var clrkey = key.ToClrValue();
            return this.dynData.Remove(clrkey);
        }

        public bool TryGetValue(Value key, out Value value)
        {
            var clrkey = key.ToClrValue();
            TValue clrvalue = default(TValue);
            if (this.dynData.TryGetValue(clrkey, out clrvalue))
            {
                value = Value.FromAny(clrvalue);
                return true;
            }

            value = Value.Nil;
            return false;
        }

        public ICollection<Value> Values
        {
            get { return ClrInterop.ToLuaValueCollection(this.data.Values); }
        }

        public Value this[Value key]
        {
            get
            {
                Value value;
                this.TryGetValue(key, out value);
                return value;
            }
            set
            {
                var clrkey = key.ToClrValue();
                var clrvalue = value.ToClrValue();
                this.dynData[clrkey] = clrvalue;
            }
        }

        public void Add(KeyValuePair<Value, Value> item)
        {
            var clrkey = item.Key.ToClrValue();
            var clrvalue = item.Value.ToClrValue();
            this.dynData.Add(clrkey, clrvalue);
        }

        public void Clear()
        {
            this.data.Clear();
        }

        public bool Contains(KeyValuePair<Value, Value> item)
        {
            dynamic clrkey = item.Key.ToClrValue();
            dynamic clrvalue = item.Value.ToClrValue();
            return this.dynData.Contains(new KeyValuePair<TKey, TValue>(clrkey, clrvalue));
        }

        public void CopyTo(KeyValuePair<Value, Value>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int Count { get { return this.data.Count; } }

        public bool IsReadOnly { get { return this.data.IsReadOnly; } }

        public bool Remove(KeyValuePair<Value, Value> item)
        {
            throw new NotImplementedException();
        }

        public IEnumerator<KeyValuePair<Value, Value>> GetEnumerator()
        {
            return this.data
                .Select(kvp => new KeyValuePair<Value, Value>(Value.FromAny(kvp.Key), Value.FromAny(kvp.Value)))
                .GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
}
